// encoding utf-8

#include <QDebug>

#include "QySciLexer.h"

#define QY_SCILEXER_STYLES "styles"
#define QY_SCILEXER_KEYWORDS "keywords"
#define QY_SCILEXER_PROPERTIES "properties"
//тест
QySciLexer::QySciLexer( QObject * parent ) : QsciLexer(parent) {

	p_blockLookback = 20;
	p_blockStartStyle = 0;
	p_blockEndStyle = 0;
	p_blockStartKeywordStyle = 0;
	p_braceStyle = 0;
	p_defaultStyle = 0;

	p_caseSensitive = false;
	p_defaultEolFill = false;

	p_language = "text";
	p_lexer = "base";

}

QySciLexer::~QySciLexer() {
}

const char * QySciLexer::language() const {

	return p_language.constData();
}

const char * QySciLexer::lexer() const {

	return p_lexer.constData();
}

QStringList QySciLexer::autoCompletionWordSeparators() const {

	return p_autoCompletionWordSeparators;
}

const char * QySciLexer::blockEnd( int * style ) const {

	if (style)
		*style = p_blockEndStyle;

	return p_blockEnd.constData();
}

int QySciLexer::blockLookback() const {

	return p_blockLookback;
}

const char * QySciLexer::blockStart( int * style ) const {

	if (style)
		*style = p_blockStartStyle;

	return p_blockStart.constData();
}

const char * QySciLexer::blockStartKeyword( int * style ) const {

	if (style)
		*style = p_blockStartKeywordStyle;

	return p_blockStartKeyword.constData();
}

int QySciLexer::braceStyle() const {

	return p_braceStyle;
}

bool QySciLexer::caseSensitive() const {

	return p_caseSensitive;
}

const char * QySciLexer::keywords( int set ) const {

	if ( keywordsSets.contains(set) )
		return keywordsSets[set].constData();

    return 0;
}

int QySciLexer::defaultStyle() const {

	return p_defaultStyle;
}

QString QySciLexer::description( int style ) const {

	if ( styleDescriptions.contains(style) )
		return styleDescriptions[style];

	return QString();
}

QVariant QySciLexer::lexerProperty( const QString & name ) const {

	if ( p_lexerProperties.contains(name) )
		return p_lexerProperties[name];

	return QVariant();
}

void QySciLexer::setLanguage( const QString & language ) {

	p_language = language.toAscii();

}

void QySciLexer::setLexer( const QString & lexer ) {

	p_lexer = lexer.toAscii();

}

void QySciLexer::setAutoCompletionWordSeparators( QStringList autoCompletionWordSeparators ) {

	p_autoCompletionWordSeparators = autoCompletionWordSeparators;

}

void QySciLexer::setLexerProperty( const QString & name, const QVariant & value ) {

	p_lexerProperties[name] = value;

// 	static QByteArray nameData, valueData;
	QByteArray nameData, valueData;

	nameData = name.toAscii();
	valueData = value.toString().toAscii();

// 	QByteArray nameData( name.toAscii() ),
// 		valueData( value.toString().toAscii() );

	// qDebug() << name << "=" << value.toString();
	// qDebug() << nameData.constData() << "=" << valueData.constData();

    emit propertyChanged( nameData.constData(), valueData.constData() );

}

#define READSTYLE( name, defaultValue ) ( propertyMap.contains( styleName + "." + name ) ? propertyMap.take( styleName + "." + name ) : QVariant(defaultValue) )

void QySciLexer::clearSettings() {

	keywordsSets.clear();
	styleDescriptions.clear();
	p_lexerProperties.clear();
	p_autoCompletionWordSeparators.clear();

}

inline QFont readFont( const QString & str ) {

	QFont font;

	if ( !font.fromString(str) )
		qWarning( "Can't read font from str \"%s\"", str.toStdString().c_str() );

	return font;
}

inline QMap<int,QByteArray> findKeywordsSets( const QString & str, QMap<QString,QVariant> & propertyMap ) {

	QMap<int,QByteArray> result;
	QMapIterator<QString,QVariant> it(propertyMap);
	QStringList keys;
	QString key;

	while ( it.hasNext() ) {

		it.next();

		key = it.key();

		if ( key.startsWith(str) ) {

			keys.append(key);

			result[ key.remove(str).toInt() ] = it.value().toString().toAscii();

		}

	}

	foreach ( QString key, keys )
		propertyMap.remove(key);

	return result;
}

inline QMap<QString,QVariant> findProperties( const QString & str, QMap<QString,QVariant> & propertyMap ) {

	QMap<QString,QVariant> result;
	QMapIterator<QString,QVariant> it(propertyMap);
	QStringList keys;
	QString key;

	// qDebug() << "findProperties" << str;

	while ( it.hasNext() ) {

		it.next();

		key = it.key();

		// qDebug() << "key" << key;

		if ( key.startsWith(str) ) {

			keys.append(key);

			result[ key.remove(str) ] = it.value();

		}

	}

	foreach ( QString key, keys )
		propertyMap.remove(key);

	return result;
}

void QySciLexer::loadPropertyFromMap( QMap<QString,QVariant> propertyMap ) {

	QStringList stylesNames;
	QColor defColor( defaultColor() ), defPaper( defaultPaper() ),
		styleColor, stylePaper;
	QFont defFont( defaultFont() ),
		styleFont;
	int lastId = 0,
		styleId;
	bool defEolFill = defaultEolFill(),
		eolFill;

	if ( propertyMap.contains(QY_SCILEXER_STYLES) )
		stylesNames = propertyMap.take(QY_SCILEXER_STYLES).toString().split(",");

	// QList<QByteArray> propNames( dynamicPropertyNames() );

	foreach ( QString styleName, stylesNames ) {

		styleName = styleName.simplified();

		styleId = READSTYLE( "id", lastId ).toInt();
		styleColor = QColor( READSTYLE( "fore", defColor ).toString() );
		stylePaper = QColor( READSTYLE( "back", defPaper ).toString() );
		styleFont = readFont( READSTYLE( "font", defFont ).toString() );
		eolFill = READSTYLE( "eolFill", defEolFill ).toBool();

		styleDescriptions[styleId] = styleName.toAscii();

		setColor( styleColor, styleId );
		setPaper( stylePaper, styleId );
		setFont( styleFont, styleId );
		setEolFill( eolFill, styleId );

		// qDebug() << "add style" << styleName << styleId << styleColor.name() << stylePaper.name() << styleFont.toString() << eolFill;

		lastId = styleId ++;

		while ( styleDescriptions.contains(lastId) )
			lastId ++;

	}

	// qDebug() << "keys" << propertyMap.keys();

	keywordsSets = findKeywordsSets( QY_SCILEXER_KEYWORDS, propertyMap );
	p_lexerProperties = findProperties( QString(QY_SCILEXER_PROPERTIES) + ".", propertyMap );

	refreshProperties();

}

#undef READSTYLE

void QySciLexer::refreshProperties() {

	// qDebug() << "lexer" << lexer();

	QStringList lpKeys( p_lexerProperties.keys() );

	foreach ( QString propName, lpKeys ) {

		// qDebug() << "propertyChanged" << qPrintable(propName) << qPrintable( p_lexerProperties[propName].toString() );

		emit propertyChanged( qPrintable(propName), qPrintable( p_lexerProperties[propName].toString() ) );

	}

}
